package at.fhooe.swa.client.service.adapter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import at.fhooe.swa.client.domain.DoubleSensor;
import at.fhooe.swa.client.domain.ISensorHistoryData;
import at.fhooe.swa.client.domain.ISensorRegister;
import at.fhooe.swa.client.domain.SensorHistoryData;
import at.fhooe.swa.client.domain.SensorRegister;
import at.fhooe.swa.client.domain.logdomain.HumidityLogRecord;
import at.fhooe.swa.client.domain.logdomain.ILogRecord;
import at.fhooe.swa.client.domain.logdomain.LightnessLogRecord;
import at.fhooe.swa.client.domain.logdomain.NoiseLogRecord;
import at.fhooe.swa.client.domain.logdomain.SmokeLogRecord;
import at.fhooe.swa.client.domain.logdomain.TemperatureLogRecord;
import at.fhooe.swa.client.service.event.IServiceListener;
import at.fhooe.swa.client.service.event.ServiceHistoryEvent;
import at.fhooe.swa.client.service.event.ServiceTrackEvent;
import at.fhooe.swa.client.util.Resources;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

public class ServiceAdapter implements IServiceAdapter
{
	List<EventListener> listeners = new ArrayList<EventListener>();
	private Socket clientSocket;
	
	private ISensorRegister register = new SensorRegister();
	private ISensorHistoryData history = null;

	private void handleSensorTrack(String json)
	{
		JsonParser parser = new JsonParser();
		JsonElement elem = parser.parse(json);
		JsonObject obj = elem.getAsJsonObject();
		
		// loop over the elements in the Json
		for (Entry<String, JsonElement> entry : obj.entrySet())
		{
			if (entry.getKey().toString().equals("sensorTime"))
			{
				register.setLastUpdateTime(entry.getValue().toString());
			}
			else
			{
				String key = entry.getKey();
				
				Double dval = null;
				Boolean bval = null;
				try
				{
					 dval = entry.getValue().getAsDouble();
				}
				catch (Exception e1)
				{
					try
					{
						 bval = entry.getValue().getAsBoolean();
					}
					catch (Exception e2)
					{
						System.err.println("This type cannot be handled by the adapter right now...");
						return;
					}
				}
				
				if (!register.sensorAlreadyRegisterd(key))
				{
					register.addSensorByName(key);
				
				}
				// Recheck if the sensor was added correctly!!
				// if the sensor is not registered in the properties file
				// the registration won't work
				if (register.sensorAlreadyRegisterd(key))
				{
					if (dval != null)
						register.getSensor(key).setCurrentValue(dval);
					else if (bval != null)
						register.getSensor(key).setCurrentValue(bval);
				}
					
			}
		}
		
//		Gson gson = new GsonBuilder().create();
//		ISensorTrack sensorTrack = gson.fromJson(json, SensorTrack.class);

	}

	private void handleSensorTracks(String json)
	{
		List<ILogRecord> logValues = null;
		String[] result1 = json.split("\\[");
		String[] result2 = result1[1].split("\\]");
		String logArray = "["+result2[0]+"]";
		
		Gson gson = new Gson();
		if(logArray.contains("temperature")){
			Type collectionType = new TypeToken<List<TemperatureLogRecord>>(){}.getType();
			logValues = gson.fromJson(logArray, collectionType);
			history = new SensorHistoryData(register.getSensor("temperature"));
		}else if(logArray.contains("humidity")){
			Type collectionType = new TypeToken<List<HumidityLogRecord>>(){}.getType();
			logValues = gson.fromJson(logArray, collectionType);
			history = new SensorHistoryData(register.getSensor("humidity"));
		}else if(logArray.contains("smoke")){
			Type collectionType = new TypeToken<List<SmokeLogRecord>>(){}.getType();
			logValues = gson.fromJson(logArray, collectionType);
			history = new SensorHistoryData(register.getSensor("smoke"));
		}else if(logArray.contains("noise")){
			Type collectionType = new TypeToken<List<NoiseLogRecord>>(){}.getType();
			logValues = gson.fromJson(logArray, collectionType);
			history = new SensorHistoryData(register.getSensor("noise"));
		}else if(logArray.contains("lightness")){
			Type collectionType = new TypeToken<List<LightnessLogRecord>>(){}.getType();
			logValues = gson.fromJson(logArray, collectionType);
			history = new SensorHistoryData(register.getSensor("lightness"));
		}
		if(!logValues.isEmpty() && history!=null){
			for(ILogRecord lr : logValues){
				history.addDataEntry(lr.getDate(), lr.getValue());
			}
		}
	}

	@Override
	public void run()
	{
		if (clientSocket == null)
		{
			boolean ok = connect();
			if (!ok)
			{
				System.err.println("Connecting to server failed!");
				return;
			}
		}
		
		BufferedReader in = null;
		try
		{
			String jsonString = null;
			in = new BufferedReader(new InputStreamReader(
					clientSocket.getInputStream()));
			while ((jsonString = in.readLine()) != null)
			{

				// parse the date we get from the server...
				if (jsonString != null)
				{
					if (jsonString.contains("clientresponse"))
					{
						handleSensorTracks(jsonString);
						fireEvent(new ServiceHistoryEvent(this, this.history));
					} else
					{
						handleSensorTrack(jsonString);
						fireEvent(new ServiceTrackEvent(this, this.register));
					}
					//fireEvent(new ServiceTrackEvent(this, this.register));
				}
			}
			
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				in.close();
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}

	}

	private void fireEvent(EventObject event)
	{
		for (EventListener listener : listeners)
		{
			if (listener instanceof IServiceListener)
				((IServiceListener) listener).handleServiceData(event);
		}
	}

	private boolean connect()
	{
		boolean status = true;
		try
		{
			InetAddress addr = InetAddress.getByName(Resources.getServiceIp());
			clientSocket = new Socket(addr, Resources.getServicePort());
		} 
		catch (IOException e)
		{
			status = false;
			e.printStackTrace();
		}

		return status;
	}

	@Override
	public void requestTracks(String dateFrom, String dateTo, String sensor)
	{
		// the PULL request to the server...
		PrintWriter out = null;
		try
		{
			out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
					clientSocket.getOutputStream())), true);
			out.println(dateFrom + "*" + dateTo + "*" + sensor);
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		} 
		finally
		{
			//out.close();
		}
	}

	@Override
	public void addListener(EventListener listener)
	{
		listeners.add(listener);
	}

	@Override
	public void removeListener(EventListener listener)
	{
		listeners.remove(listener);
	}
	
	public void test()
	{
		String testjSon = "{" +
			"\"sensorTime\":\"Jan 18, 2013 7:25:18 PM\"," +
			"\"temperature\":21.0," +
			"\"humidity\":72.0," +
			"\"smoke\":false," +
			"\"lightness\":61.0," +
			"\"noise\":22.0," +
			"\"smokeConstant\":0"+
		"}";
		
		handleSensorTrack(testjSon);
		fireEvent(new ServiceTrackEvent(this, this.register));
	}

}
